
title	' Modem Supervisor for Compupro MPM 8-16'

;-----------------------------------------------------------------------;
;    MSUP - Modem SUPervisor						;
;									;
;    Version 1.1	08/22/84       <AKS>				;
;									;
;    Copyright (C) 1984	 Alex Soya, PO Box 121, Melbourne Beach,	;
;						Fl, 32951		;
;									;
;	MSUP is released to the public domain. Anyone who wishes to	;
;	USE MSUP on his system may do so.  The author assumes no	;
;	responsibility or liability for use of MSUP.			;
;									;
;	The author, Alex Soya, has sole rights to this program. MSUP	;
;	may not be sold without the express, written permission by	;
;	the author.							;
;									;
;    Purpose:								;
;		To intercept Console I/O functions to the XIOS and	;
;	handle them localy. To supervise the allocation of Comunication ;
;	channels to modem programs.					;
;									;
;		This version is for the CompuPro interfacer 3/4		;
;	serial board. Up to two boards (max 16 devices) are supported	;
;	The boards must have interrupt jumpers and switches set		;
;	as per CompuPro's instructions. The received data is buffered   ;
;	in a local queue structure. This RSP can also be used with any	;
;	standard terminal if a modem is not connected. The only		;
;	difference is that the received data does not have the		;
;	parity bit removed which is infact an annoying feature in the	;
;	XIOS by CompuPro.						;
;									;
;	The mapping of MPM console numbers to Interfacer 3/4		;
;	relative user nos uses the same translation as that of		;
;	CompuPro for compatibility reasons:				;
;									;
;	Interfacer 3/4 relative user:	 MPM Console:  MPM Printer:	;
;  F	-----------------------------	 ------------  ------------	;
;  I				    7		    1		-	;
;  R				    6		    2		-	;
;  S	Interfacer 3 & 4	    5		    -		1	;
;  T				    4		    -		0	;
;	---------------------------------------------------------	;
;  B				    3		    3		-	;
;  O	Interfacer 3 only	    2		    4		-	;
;  A				    1		    5		-	;
;  R				    0		    6		-	;
;  D									;
; --------------------------------------------------------------------	;
;  S				    8		    -		 2	;
;  E	Interfacer 3 & 4	    9		    7		 -	;
;  C				   10		    8		 -	;
;  O				   11		    9		 -	;
;  N	----------------------------------------------------------	;
;  D				   12		   10		 -	;
;	Interfacer 3 only	   13		   11		 -	;
;  B				   14		   12		 -	;
;  O				   15		   13		 -	;
;  A									;
;  R									;
;  D									;
;									;
;	To customize this map change the CTRMAP AND RTCMAP tables.	;
;					       =====			;
;-----------------------------------------------------------------------;



true	equ	-1
false	equ	not true


cr	equ	13		; Carriage Return
lf	equ	10		; Line Feed
eof	equ	1ah		; End Of File marker
xon	equ	'Q'-40h		; ^Q
xoff	equ	'S'-40h		; ^S



; Consoles handled by RSP:
;
;
lowcon	  equ	  1		; Lowest Console number handled
highcon	  equ	  13		; Highest Console number handled
lowprnt	  equ	  0		; Lowest Printer handled
highprnt  equ	  2		; Highest Printer handled

qdepth	equ	128			; Lenght of circular que buffers




; Interrupt Vector addresses:
; The interfacer 3/4 uses VI2 for receive and VI3 for transmit. The particular
; Usart or device that interrupted must be determined in the corresponding
; ISR
;
;
;
rint2	equ	(40h+2)*4		; Receive interrupt vector address VI2
tint3	equ	(40h+3)*4		; Transmit interrupt vect. address VI3



; Flags used by this RSP:
; flags 30h through 50h are used by this rsp and should not be used by any
; other processes.
;
;
;
fbase  equ	30h			; lowest flag used
fwait  equ	fbase			; Flag to wait for ever
			; fbase+1h through fbase+16 are for receive
			; ready, fbase+17 through fbase+32  are for
			; transmit ready on devices 1 - 16



; MPM function numbers
;
;
f_open	equ	15		; Open Disk File Function
f_close equ	16		; Close Disk File
f_rseq	equ	20		; Read Sequential from Disk file function
f_dmao	equ	26		; Set DMA Offset
f_dmab	equ	51		; Set DMA Base
f_poll	equ	131		; Poll Device
waitf	equ	132		; Wait for selected flag to set
setf	equ	133		; Set selected flag to wake up waiting process
f_mkque equ	134		; Make a Que
f_opque equ	135		; Open Que
f_wrque equ	139		; Write Que
getsys	equ	154		; Get sysdat segment to ES



; SYSDAT offsets
;
;
supentr equ	0		; Supervisor entry offset
xiossys equ	28h		; offset to XIOS entry in system data area
dispsys equ	38h		; offset to dispatcher entry address



; Interrupt controller comands
;
;
;
nseoi	equ	20h		; none specific End of Interrupt

				; This is for the PICs located on the
				; System Support 1 board. If you use
				; a different Interrupt Controller you need
				; to modify any of the PIC dependent routine
				; (service) for your environment



; System Support I  PIC ports:
;
;
;
ss1base equ	50h		; System Support I base port
mpic0	equ	ss1base+0	; Master PIC port 0
mpic1	equ	ss1base+1	; Master PIC port 1
spic0	equ	ss1base+2	; Slave PIC port 0
spic1	equ	ss1base+3	; Slave PIC port 1



; CompuPro Interfacer 3/4 ports:
;
;
;
i4base	equ	10h		; Interfacer 3/4 base port
i4data	equ	i4base		; Data port
i4stat	equ	i4base+1	; Status port
i4mode	equ	i4base+2	; Usart mode register
i4comd	equ	i4base+3	; Usart Command register
i4tint	equ	i4base+4	; Transmit interrupt status register
i4rint	equ	i4base+5	; Receive Interrupt status register
i4slct	equ	i4base+7	; Relative user select register



; Status port bit maps (on read):
;
;
;
i4tbmt	equ	01h		; Transmit buffer empty
i4dav	equ	02h		; Data available
i4txem	equ	04h		; Change in DSR or DCD or Transmit shift empty
i4pe	equ	08h		; Parrity error on character received
i4or	equ	10h		; Overrun error
i4fe	equ	20h		; framing error
i4dcd	equ	40h		; Data Carrier Detect condition
i4dsr	equ	80h		; Data Set Ready Condition


; Set up file constants:
;
;
;
lnlen	equ	80		; max line length of COMCH, TTYS or LPRS entry



;-----------------------------------------------------------------------;
; exec: Rsp execution entry.						;
;									;
;	The RSP starts executing here. Here the COMCH, TTYSC and LPRSC	;
;	files are read and used to set up the interrupt masks for the	;
;	Interfacer 3/4 board.						;
;									;
;	The Mutual eXclusion ques MXmodem1 through MXmodem8 are made	;
;	and written to if the corresponding console number in the	;
;	COMCH file exists. The modem program must open the MXmodemN	;
;	ques with N beeing the number of a Comm. channel. If the modem	;
;	program reads from the que it effectively blocks any other	;
;	process to gain access to that que and thus the corresponding	;
;	Communication Channel.						;
;									;
;	Also the XIOS entry point is moved to the local XIOS function	;
;	intercepter.							;
;									;
;-----------------------------------------------------------------------;
;
;
;
exec:	mov	ax,cs			; set up 8080 model (cs=ds)
	pushf				; disable interrupts while messing
	cli				; with stack regs
	mov	ss,ax
	mov	sp,offset lstack
	mov	ds,ax

	mov	cl,146			; Attach Console so Shell does not
	int	224			; grab it.

	popf
	mov	cl,getsys		; Get SYSDAT to ES
	int	224
	pushf				; stop interrupts again
	cli				; while changing interrupt vectors

	push	ds			; set up interrupt vector addresses
	mov	ax,0			; vectors are in segment 0
	mov	ds,ax
	mov	word ptr .rint2,offset i4rxint	; receive interrupt handler
	mov	word ptr .rint2+2,cs	; and our segment
	mov	word ptr .tint3,offset i4txint	; transmit interrupt handler
	mov	word ptr .tint3+2,cs	; and segment
	pop	ds
 
	mov	ax,es:.xiossys		; get current XIOS offset
	mov	xios,ax			; build real xios dispatch address
	mov	ax,es:.xiossys+2	; get segment of real xios
	mov	xios+2,ax
	mov	ax, offset xintcpt	; overlay xios interceptors address
	mov	es:.xiossys,ax		; to old xios vectors
	mov	ax,cs
	mov	es:.xiossys+2,ax

	mov	ax,es:.supentr+2	; get segment of MPM supervisor
	mov	supvsr+2,ax		; and keep to us

	mov	ax,es:.dispsys		; Now get dispatchers offset
	mov	disp,ax
	mov	ax,es:.dispsys+2	; and its segment
	mov	disp+2,ax

	popf				; now we can resume with interrupts


	call	rdsetup			; set up MXmodemN ques and prepare
					; masks for interfacer 3/4
	mov	cl,9			; send message: 'we are active' to
	mov	dx, offset hellomsg	; system console
	int	224

	mov	cl,147			; detach from Console, so Shell can
	int	224			; get a hold of it.

forever:mov	cl,waitf		; CODE MAY BE ADDED HERE TO ALLOW
	mov	dl,fwait		; REMOTE TERMINALS TO BE MONITORED FOR
	int	224			; PROCCESS ABORTION ON LOSS OF CARRIER
	jmps	forever			; AND LOGON PROGRAM LOAD



hellomsg	db	cr,lf,' Msup - Modem Supervisor active. (C) Alex Soya'
		db	cr,lf,'$'





;-----------------------------------------------------------------------;
;									;
; rdsetup:   Read the set up files TTYSC, LPRSC, and COMCH		;
;									;
;	     These files contain the parameters for the Consoles,	;
;	     Printers, and Comunication Channels.			;
;	     They are read in here to determine which channels		;
;	     on the Interfacer 3/4 board are used so that the proper	;
;	     Interrupt mask can be set up.				;
;									;
;	     The files TTYSC and LPRSC are as per COMPUPROS specs for	;
;	     their TTYS and LPRS files used by SHELL.			;
;									;
;	     The file COMCH is used to determine which Interfacer 3/4	;
;	     device is used as a Communications Channel for the		;
;	     Modem. Proper Mutual EXclusion Ques are set up depending	;
;	     on the COMCH file entries.					;
;									;
;	     The COMCH format is as:					;
;									;
;	     N: Comment <CR><LF>					;
;									;
;	     Where N = the Console number corresponding to the		;
;	     Modem Port.						;
;									;
;	     eg:							;
;		 2: Phone line 1					;
;		 3: Phone line 2					;
;									;
;	     will turn consoles 2 and 3 into Comm. channels. DO NOT	;
;	     include these into the TTYS and TTYSC files as they will	;
;	     then be grabed by the shell.				;
;									;
;-----------------------------------------------------------------------;
;
;
;
rdsetup:
	mov	fopflg,0		; File is still closed
nxcom:	mov	dx,offset comfcb	; Open COMCH file and prepare to read
	call	getline			; one line.
	jne	ttyf			; No more in ComCH file.
	call	parscom			; proccess one line
	jmps	nxcom			; and get next line

ttyf:	mov	fopflg,0		; File Closed now
nxtty:	mov	dx,offset ttyfcb	; now process the TTYS file
	call	getline
	jne	lprf
	call	parstty
	jmps	nxtty
;
lprf:	mov	fopflg,0		; File Closed again
nxlpr:	mov	dx, offset lprfcb	; and finaly the LRPS file
	call	getline
	jne	done
	call	parslpr
	jmps	nxlpr
done:	ret
;
;
;
;-----------------------------------------------------------------------;
; getline:    Get one line from file of which the FCB is in DX.		;
;	      If fopflg = 0, the file is closed and is opened first	;
;	      to read the next line.					;
;	      Closes file if no more data available.			;
;									;
; Entry	 ->  DX = FCB offset						;
;	     fopflg = 0 if file closed, Not 0 if file already open	;
;									;
; Return ->  lnbuff  contains one physical line including cr,lf to	;
;		     indicate the end of the line.			;
;									;
;	     fopflg = FFh after file was opened.			;
;									;
;-----------------------------------------------------------------------;
;
;
;
getline:
	push	dx			; save FCB offset
	mov	di, offset lnbuff	; point to line buffer
	mov	si,dmasrc		; get dma posit from last move
	mov	bx,dmaoff		; and the count
	cmp	byte ptr fopflg,0	; first line we are getting ?
	jne	search			; no, see whats in dma buffer

	mov	dx, offset dmabuf	; Yes, open file first 
	mov	cl, f_dmao
	int	224
;
	mov	dx,cs			; Set DMA Segment address
	mov	cl, f_dmab
	int	224
;
	pop	dx ! push dx		; get FCB offset
	mov	cl, f_open		; open the file
	int	224
;
	mov	di, offset lnbuff	; init line buffer offset
	cmp	al,0ffh
	jne	rdnxt			; if open successfull, read record
	or	al,al
	pop	dx
	ret				; else return to caller
;
;
;
rdnxt:	mov	fopflg,-1		; the file is open now
beatme: pop	dx ! push    dx		; Read next record of file
	mov	cl, f_rseq
	int	224
	xor	bx,bx
	or	al,al
	mov	si, offset dmabuf	; start at beginning of buffer
	je	srterm			; if good read, move one line to line
	jmp	clcom			; buffer, else close file.
;
srterm: mov	ax,ds			; force es=ds
	mov	es,ax
;
search: cmp	dmabuf[bx],lf		; search for end of line marker
	je	lf_fnd			; or until end of buffer is reached
	cmp	dmabuf[bx],eof		; is it the end of the file
	je	clcom			; that means we are done
	cmp	bx,127			; end of buffer reached ?
	je	en_buf
	inc	bx
	jmps	search			; nope... keep looking
;
en_buf: inc	bx
	mov	dx,si
	sub	dx, offset dmabuf
	mov	cx,bx			; get # of bytes to move
	sub	cx,dx			; adjust for last move
rep	movsb				; copy part of line over to lnbuffer
	jmp	beatme			; get rest of line and copy it.
;
lf_fnd: inc	bx
	mov	dx,si
	sub	dx, offset dmabuf
	mov	cx,bx 
	sub	cx,dx
rep	movsb
;
	pop	dx			; get back FCB
	xor	al,al			; tell caller new line is ready
	mov	word ptr dmasrc,si	; save si for next time round
	mov	word ptr dmaoff,bx	; same with bx
	ret
;
;
clcom:	pop	dx			; close file
	mov	cl, f_close
	int	224
	mov	al,-1			; and indicate to caller
	or	al,al			; that its all over
	ret				; and all done
;
;
;
parscom:mov	al,lnbuff		; get first charcter in line
	cmp	al,30h+1			; is it in range ?
	jl	pdn
	cmp	al,30h+8		; we support up to 8 com channels
	jg	pdn
	mov	qpdnam+7,al
	mov	cl,f_mkque			; and make the que
	push	bx
	sub	al,30h				; Form interrupt mask
	call	formsk
	dec	al
	rol	al,1				; compute que descriptor
	mov	bl,al				; offset
	mov	bh,0
	mov	dx,qdtbl[bx]
	pop	bx
	int	224
	mov	cl,f_opque			; open the que 
	mov	dx, offset mxqpb
	int	224
	mov	cl,f_wrque			; Write to que
	mov	dx, offset mxqpb		; so now its available
	int	224
pdn:	ret	
;
;
parstty:
	mov	al,lnbuff		; get the first char in a line
	cmp	al,30h+lowcon
	jl	ttyld
	cmp	al,30h+9		; in range ?
	jg	ttyld			; nope... skip it
	sub	al,30h			; make device number
	call	formsk			; yeap, add to interrupt mask
	call	protc			; determine protocoll used
ttyld:	ret				; done with this line.
;
;
parslpr:
	mov	al,lnbuff		; get the first char in a line
	cmp	al,30h+lowprnt
	jl	lprld
	cmp	al,30h+highprnt		; in range ?
	jg	lprld
	sub	al,30h-highcon-1	; make a device number
	call	formsk
	call	protc			; determine protocoll used
lprld:	ret



;-----------------------------------------------------------------------;
;									;
; formsk:	Form Interrupt Mask					;
;									;
; Entry	 -> al = device number (1 to 16)				;
;									;
; return -> imask = imask or (bit corresponding to device number)	;
;									;
;-----------------------------------------------------------------------;
;
;
;
formsk: push	ax
	push	cx			; save'm
	mov	cl,al			; convert to exact user number
	call	conctr
	mov	ax,1			; make mask for this user number
	rol	ax,cl
	or	word ptr imask,ax	; or mask into present mask
	pop	cx
	pop	ax			; get'm back
	ret				; and we are done
;
;


imask	dw	0		; mask to enable interrupts on I3/4 Interrupt
				; mask registers
				; low byte  = first board 
				; high byte = second board

;-----------------------------------------------------------------------;
;									;
;  protc:   Determine the protocol used on device			;
;									;
;  entry  ->  al= device number						;
;	      lnbuff = input line from set up file TTYSC or LPTSC	;
;									;
;  return ->  fills in table hndshk for the device			;
;									;
;-----------------------------------------------------------------------;
;
;
;
protc:	push	ax
	push	bx
	push	ax
	mov	bx, offset lnbuff	; point to line buffer and
	call	fndel			; and find first delimiter
	call	fndel			; find second delimiter
	inc	bx			; now we should have handshake value
	mov	al,byte ptr [bx]
	pop	bx			; bx=device number
	xor	bh,bh			; make 16 bit index
	sub	al,30h			; got handshake, deasccie
	cmp	al,3			; in range ?
	jg	def			; nope, use default
	cmp	al,0
	jb	def
	mov	byte ptr hndshk[bx],al	; and stuff handshake argument
	pop	bx
	pop	ax
	ret
;
def:	mov	byte ptr hndshk[bx],0	; default is no handshake
	pop	bx
	pop	ax
	ret
;
;
fndel:	inc	bx			; skip first one
	cmp	byte ptr [bx],':'	; match ?
	jne	fndel			; Nope, try next one
delfn:	ret				; yeap.. return to caller, bx=match
;
;
;
hndshk	db	0,0,0,0		; hand shake table 0= no hand shake
	db	0,0,0,0		;		   1 = DTR
	db	0,0,0,0		;		   2 = Xon Xoff
	db	0,0,0,0		;		   3 = DTR & Xon Xoff
	db	0		; bit 7 indicates X-ON awaited
	db	0		; for device 1 through 16 (0 handled in XIOS)




qdtbl	dw	offset mxqd1			; Que descriptor table
	dw	offset mxqd2
	dw	offset mxqd3
	dw	offset mxqd4
	dw	offset mxqd5
	dw	offset mxqd6
	dw	offset mxqd7
	dw	offset mxqd8

quebuf	rb 10			; que descriptors must be unique in RSPs

mxqd1	dw	0		; Mutual exclusion que descriptior
	dw	0
	dw	3		; a Mutual exclusion que that can not be
	db	'MXmodem1'	; be deleted
	dw	0		; message lenght is 0
	dw	1		; 1 message at a time
	dw	0
	dw	0
	dw	0
	dw	0
	dw	offset quebuf	; must point to buffer for RSP


mxqd2	dw	0		; Mutual exclusion que descriptior
	dw	0
	dw	3		; a Mutual exclusion que that can not be
	db	'MXmodem2'	; be deleted
	dw	0		; message lenght is 0
	dw	1		; 1 message at a time
	dw	0
	dw	0
	dw	0
	dw	0
	dw	offset quebuf	; must point to buffer for RSP


mxqd3	dw	0		; Mutual exclusion que descriptior
	dw	0
	dw	3		; a Mutual exclusion que that can not be
	db	'MXmodem3'	; be deleted
	dw	0		; message lenght is 0
	dw	1		; 1 message at a time
	dw	0
	dw	0
	dw	0
	dw	0
	dw	offset quebuf	; must point to buffer for RSP


mxqd4	dw	0		; Mutual exclusion que descriptior
	dw	0
	dw	3		; a Mutual exclusion que that can not be
	db	'MXmodem4'	; be deleted
	dw	0		; message lenght is 0
	dw	1		; 1 message at a time
	dw	0
	dw	0
	dw	0
	dw	0
	dw	offset quebuf	; must point to buffer for RSP


mxqd5	dw	0		; Mutual exclusion que descriptior
	dw	0
	dw	3		; a Mutual exclusion que that can not be
	db	'MXmodem5'	; be deleted
	dw	0		; message lenght is 0
	dw	1		; 1 message at a time
	dw	0
	dw	0
	dw	0
	dw	0
	dw	offset quebuf	; must point to buffer for RSP


mxqd6	dw	0		; Mutual exclusion que descriptior
	dw	0
	dw	3		; a Mutual exclusion que that can not be
	db	'MXmodem6'	; be deleted
	dw	0		; message lenght is 0
	dw	1		; 1 message at a time
	dw	0
	dw	0
	dw	0
	dw	0
	dw	offset quebuf	; must point to buffer for RSP


mxqd7	dw	0		; Mutual exclusion que descriptior
	dw	0
	dw	3		; a Mutual exclusion que that can not be
	db	'MXmodem7'	; be deleted
	dw	0		; message lenght is 0
	dw	1		; 1 message at a time
	dw	0
	dw	0
	dw	0
	dw	0
	dw	offset quebuf	; must point to buffer for RSP
;
;
mxqd8	dw	0		; Mutual exclusion que descriptior
	dw	0
	dw	3		; a Mutual exclusion que that can not be
	db	'MXmodem8'	; be deleted
	dw	0		; message lenght is 0
	dw	1		; 1 message at a time
	dw	0
	dw	0
	dw	0
	dw	0
	dw	offset quebuf	; must point to buffer for RSP


mxqpb	dw	0		; MXmodemn Que Parameter Block
	dw	0
	dw	1
	dw	offset quebuf
qpdnam	db	'MXmodem '
;
;
;
;
comfcb	db	1,'COMCH   '	; dr,f1-f8
	db	'   '		; t1-t3
	db	0		; ex
	db	0,0		; cs,rs
	db	0		; rc
	db	0,0,0,0,0	; d0
	db	0,0,0,0,0	; d5..
	db	0,0,0,0,0	; d10
	db	0		; dn
	db	0		; cr
	db	0,0,0		; r0,r1,r2
;
;
;
ttyfcb	db	1,'TTYSC   '	; dr,f1-f8
	db	'   '		; t1-t3
	db	0		; ex
	db	0,0		; cs,rs
	db	0		; rc
	db	0,0,0,0,0	; d0
	db	0,0,0,0,0	; d5..
	db	0,0,0,0,0	; d10
	db	0		; dn
	db	0		; cr
	db	0,0,0		; r0,r1,r2
;
;
;
lprfcb	db	1,'LPRSC   '	; dr,f1-f8
	db	'   '		; t1-t3
	db	0		; ex
	db	0,0		; cs,rs
	db	0		; rc
	db	0,0,0,0,0	; d0
	db	0,0,0,0,0	; d5..
	db	0,0,0,0,0	; d10
	db	0		; dn
	db	0		; cr
	db	0,0,0		; r0,r1,r2
;
;
;
fopflg	db	0		; fopflg to flag if first time access to file
dmabuf	rb	128		; dma buffer
dmasrc	dw	0		; filled in later
dmaoff	dw	0		; same with him
lnbuff	rb	lnlen		; 80 byte line buffer.






;-----------------------------------------------------------------------;
; xintcpt: Intercept calls to the xios and pass control to internal	;
;	   handler.							;
;									;
; Entry	   ->  al =  XIOS function number				;
;	       cx =  First Argument					;
;	       dx =  Second Argument					;
;									;
; Return   ->  ax = bx - return value or error code			;
;									;
;-----------------------------------------------------------------------;
;
;
xintcpt:push	ds		; save DS of caller (saved on his stack)
	push	es		; es must be the same when returning to SUP
	mov	bx,cs		; we need our own DS here
	mov	ds,bx
	mov	bl,al		; Get Xios function number
	xor	bh,bh		; make 16 bit
	rol	bx,1		; compute index into jump table
	jmp	functbl[bx]	; call the function



;-----------------------------------------------------------------------;
;									;
;  realxios: If a function is to be handled by the real xios		;
;	     this routine passes control to the real xios after		;
;	     restoring the DS and ES register of the calling process.	;
;									;
; Entry	   ->  al =  XIOS function number				;
;	       cx =  First Argument					;
;	       dx =  Second Argument					;
;									;
; Return   ->  is from XIOS as per XIOS return parameters.		;
;									;
;-----------------------------------------------------------------------;
;
;
realxios:
	pop	es
	pop	ds			; get them back
	jmpf	dword ptr xios



;-----------------------------------------------------------------------;
;									;
;  retcpt:  Return from localy handled xios function.			;
;									;
;  Entry  ->   ax = return argument					;
;									;
;  Return ->   To calling process with bx=ax as per XIOS specs		;
;	       DS poped of local stack and thus restored to callers	;
;	       value							;
;									;
;-----------------------------------------------------------------------;
;
;
retcpt: pop	es			; return last users Data segment
	pop	ds			; and extra segment
	mov	bx,ax			; bx=ax return values
	retf				; and back to caller




;-----------------------------------------------------------------------;
; conin:								;
; const:	Test if device	is handled localy for input, status	;
; conout:	and output service. If not jumpt to corresponding	;
; lstout:	function in the real XIOS				;
; lstst:								;
; polldev:								;
;-----------------------------------------------------------------------;
;
;
conin:	cmp	cl,lowcon		; Check if the console is handled
	jb	realxios		; localy. If not, let the XIOS handle
	cmp	cl,highcon		; it
	jg	realxios
	call	inchr
	jmp	retcpt
;
const:	cmp	cl,lowcon 
	jb	realxios
	cmp	cl,highcon
	jg	realxios 
	call	qst
	jmp	retcpt
;
conout: cmp	dl,lowcon
	jb	realxios
	cmp	dl,highcon
	jg	realxios
	call	outchr
	jmp	retcpt
;
lstout: cmp	dl,lowprnt
	jb	realxios
	cmp	dl,highprnt
	jg	realxios
	add	dl,highcon+1	; make device number
	call	outchr
	jmp	retcpt
;
lstst:	cmp	cl,lowprnt
	jb	realxios
	cmp	cl,highprnt
	jg	realxios
	call	stlst
	jmp	retcpt
;
;
;
;
polldev:
	cmp	 cl, 0			; intercept Poll devices 0 to 15
	jb	 realxios
	cmp	 cl, 15
	jg	 realxios
	call	 pdsr			 ; valid port, so go an poll it
	jmp	 retcpt



;-----------------------------------------------------------------------;
;									;
; functbl  XIOS function table. Each entry in this table contains	;
;	   the offset for the corresponding function number.		;
;									;
;	   You may intercept your own XIOS functions here if you wish	;
;	   by changing the corresponding entry to the offset of your	;
;	   local handler. If a function is to be handled by the actual	;
;	   XIOS enter the offset of REALXIOS.				;
;									;
;									;
;									;
;-----------------------------------------------------------------------;
;
;
functbl dw	offset const		; 0 Console status
	dw	offset conin		; 1 Console input
	dw	offset conout		; 2 Console output
	dw	offset lstout		; 3 List output
	dw	offset realxios		; 4 Punch output
	dw	offset realxios		; 5 Reader input
	dw	offset realxios		; 6 Home
	dw	offset realxios		; 7 Select disk
	dw	offset realxios		; 8 Set track
	dw	offset realxios		; 9 Set sector
	dw	offset realxios		;10 Set DMA address
	dw	offset realxios		;11 Read a record
	dw	offset realxios		;12 Write a record
	dw	offset lstst		;13 List status
	dw	offset realxios		;14 Sector translation
	dw	offset realxios		;15 Set DMA segment
	dw	offset realxios		;16 Get segment table
	dw	offset polldev		;17 Poll selected device
	dw	offset realxios		;18 Enable tick clock
	dw	offset realxios		;19 Disable tick clock
	dw	offset realxios		;20 Return max. number of consoles
	dw	offset realxios		;21 Return max. number of list devices
	dw	offset realxios		;22 Select memory
	dw	offset realxios		;23 Idle
	dw	offset realxios		;24 Flush buffers



;-----------------------------------------------------------------------;
;									;
; inchr:  Input a character from que. If que is empty wait for a	;
;	  character to be put into it by ISR.				;
;									;
; Entry	  -> cl = MPM Console Number					;
;									;
; Return  -> al = Character input					;
;									;
;-----------------------------------------------------------------------;

inchr:	call	mapctq			; map console to que offset
	call	qempt			; Check if there is anything in the que
	jne	inchr1			; al=ff and NZ if a character is ready

	push	cx			; save console number
	mov	dl,fbase
	add	dl,cl			; wait for flag corresponding to this
	mov	cl,waitf		; console to be set indicating a char
	call	supif			; has arrived
	pop	cx			; restore console number
	jmp	inchr			; in case of erroneous flag set

inchr1: pushf				; No interrupts now ......
	cli
	call	qdel			; get a character from the que
	popf
	ret				; and exit back to caller


;-----------------------------------------------------------------------;
;									;
; qst:	Return Status of Que for corresponding Console			;
;	The first call to here will also enable the interupt mask	;
;	register on the Interfacer 3/4 board. This way any console	;
;	not in the TTYS file can still be enabled if so required.	;
;	Done here, because on the CompuPro system all internal set up	;
;	is done before entering Multi User Mode. Here we can be		;
;	relatively sure that all is done by the SHELL before we stick	;
;	our stuff in.							;
;									;
; Entry	 -> cl = MPM Console Number					;
;									;
; Return -> al =  00 if no character ready				;
;		  ff if character ready					;
;									;
;-----------------------------------------------------------------------;
;
;
qst:	cmp	setmsk,0		; Is Interrupt mask already set ?
	jne	qst1			; yeap, so just get the status.
	pushf
	cli
	xor	al,al			; first select first board
	out	i4slct,al
	mov	ax,word ptr imask
	out	i4rint,al		; now we got the mask set up
	or	byte ptr setmsk,al
	mov	al,8			; and the second board
	out	i4slct,al
	xchg	al,ah
	out	i4rint,al
	or	byte ptr setmsk,al	; flag that we dont do it again
	popf

qst1:	call	mapctq			; find que for this console
	call	qempt			; check if anything is in the que
					; al = 0 if no character is ready
					; al = ff if character is waiting to be
	ret				; picked up.

setmsk	db	0		; 0 indicates mask not set up yet.



;-----------------------------------------------------------------------;
;									;
; outchr:  Output a character to console				;
;									;
; Entry	 -> cl = character						;
;	    dl = device number						;
;									;
; Return -> none							;
;									;
;-----------------------------------------------------------------------;
;
;
;
outchr: push	cx			; save the character
	mov	cl,dl			; get device number
	call	conctr			; Convert to Interfacer 3/4 user #
	xor	dh,dh			; make 16 bit device number
	mov	bx,dx			; make index
	test	byte ptr hndshk[bx],3	; using DTR or XON/XOFF handshakes ?
	je	nhnd			; nope ignore it
	call	pdsr			; yeap, see if dsr indicates ready
	or	al,al			; Device busy ?
	jne	nhnd			; nope it ok.

	push	bx
	push	cx			; yeap, then put us on poll list
	push	dx
	mov	dl,cl			; set up for MPM poll function
	mov	cl,f_poll
	call	supif			; will return when dsr is ready
	pop	dx
	pop	cx			; now we are ready
	pop	bx

nhnd:	mov	ch,cl			; user port in ch, console in dl
	mov	ax,cx
	pop	cx			; get back character
	mov	ch,ah
	xchg	ch,cl			; ch= character, cl = exact user
	pushf				; cant have interrupts now
	cli
	call	select			; select proper usart
	in	al,i4stat		; get USART status
	popf
	test	al,i4tbmt		; ready to send a char ?
	jnz	i4out			; yeap send him out..

	push	cx			; keep'm
	mov	ax,1			; set twmask to wait
	shl	ax,cl			; compute mask
	or	word ptr twmsk,ax
	mov	ax,word ptr twmsk	; send currently active masks
	pushf
	cli
	xor	cl,cl
	call	select
	out	i4tint,al		; to enable interrupts on first board
	mov	cl,8
	call	select
	mov	al,ah
	out	i4tint,al		; and the second board
	popf

	push	dx
	add	dl,fbase+16		; compute flag
	mov	cl,waitf		; Wait for Tx flag to set
	call	supif
	pop	dx
	pop	cx

i4out:	pushf				; cant have interrupts now
	cli
	mov	al,ch			; get character
	call	select			; select uart
	out	i4data,al		; send character
	popf				; interrupts ok again
	ret				; and back to caller



;-----------------------------------------------------------------------;
;									;
; stlst:  Return List device output status				;
;									;
; entry -> cl = list device number					;
;									;
; return -> al = ffh if device ready					;
;		 0   if device not ready				;
;									;
;-----------------------------------------------------------------------;
;
;
;
stlst:	add	cl,highcon+1		; make device number
	call	conctr			; convert to i4 user number
	pushf				; no interrupts now
	cli
	call	select			; select proper port
	in	al,i4stat		; get status
	popf				; interrupts ok now
	test	al,i4tbmt		; ready ?
	jnz	lstrdy			; yeap.. go say so
	xor	al,al			; nope
	ret
lstrdy: call	pdsr			; USART is ready, but what about the
	ret				; printer itself ?



;-----------------------------------------------------------------------;
; pdsr:	   Poll DSR. This is Xios function 17 which is not used		;
;	   in the CompuPro XIOS. Used by MSUP to poll the DSR line	;
;	   for DTR handshaking, and Xon/Xoff status.			;
;	   Other systems which need to use Poll device numbers that	;
;	   are not assigned yet.					;
;									;
; Entry	 -> CL = Device number 0 through 15 beeing ports 0 through 15	;
;		 on Interfacer 3/4 board.				;
;									;
; Return -> AL = FFh if device ready					;
;		 00h if not ready					;
;									;
;-----------------------------------------------------------------------;
;
;
;
pdsr:	pushf				; disable interrupts
	cli
	call	select			; select USART
	in	al,i4stat		; get status
	popf				; we can have interrupts again
	push	bx
	push	cx			; save'm
	push	dx
	call	conrtc			; make device number
	mov	bl,cl			; make it index to handshake table
	xor	bh,bh
	mov	dl,byte ptr hndshk[bx]	; get handshake status
	and	dl,2+128		; XOFF active ?
	cmp	dl,2+128
	mov	dl,0ffh			; assume its not active
	jne	podsr			; Nope, not active for sure
	xor	dl,dl			; it is active, so device not ready

podsr:	test	byte ptr hndshk[bx],1	; are we using DTR handshake ?
	je	dsrset			; nope so DSR is set anyway

	test	al,i4dsr		; dsr set ?
	jne	dsrset			; yeap go set flags
	xor	al,al			; nope, not ready say so
	jmps	pdtdn
dsrset: or	al,0ffh			; its ready, say so 
pdtdn:	and	al,dl			; mask in XOFF status
	pop	dx
	pop	cx
	pop	bx			; restore'em 
	ret				; poll is done



;-----------------------------------------------------------------------;
;									;
; mapctq:  Map Console to Que offset					;
;									;
; Entry	 -> cl = Console Number						;
;									;
; Return -> si = Que offset						;
;									;
;-----------------------------------------------------------------------;
;
;
mapctq: push	bx			; save him
	mov	bl,cl			; make 16 bit console number
	xor	bh,bh
	sub	bx,lowcon		; first handled console gets first que
	rol	bx,1			; *2 so its index into table
	mov	si,quetbl[bx]		; get que offset to si
	pop	bx
	ret
;
;
quetbl	dw	offset que1		; Table containing Que offsets
	dw	offset que2
	dw	offset que3
	dw	offset que4
	dw	offset que5
	dw	offset que6
	dw	offset que7
	dw	offset que8
	dw	offset que9
	dw	offset que10
	dw	offset que11
	dw	offset que12
	dw	offset que13
	dw	offset que14
	dw	offset que15
	dw	offset que16	; we could have up to 16 input devices !



;-----------------------------------------------------------------------;
;									;
; i4rxint:  Interfacer 4 vector for receive data interrupts.		;
;									;
;-----------------------------------------------------------------------;
;
;
;
i4rxint:
	push	dx			; save him here.. restored by service
	mov	dx,offset i4risr	; address of actual ISR
	jmp	service			; jump to ISR via service



;-----------------------------------------------------------------------;
;									;
; i4txint:  Interfacer 3/4 vector for transmit ready interrupts.	;
;									;
;-----------------------------------------------------------------------;
;
;
;
i4txint:
	push	dx			; save her
	mov	dx,offset i4tisr	; Transmit ready ISR offset
	jmp	service			; and service it



;-----------------------------------------------------------------------;
;									;
; i4risr: Interfacer 3/4 Interrupt service routine.			;
;	  Determines which console caused an interrupt to occur		;
;	  and reads the character into the corresponding que.		;
;	  Sets proper flag to wake up sleeping proccess.		;
;									;
;									;
;-----------------------------------------------------------------------;
;
;
i4risr: mov	cl,15			; start with highest exact user
rescan: call	select			; select user to be scanned
	mov	bx,1			; make mask for this port
	rol	bx,cl
	test	word ptr imask,bx	; valid device ?
	je	nxtsn			; nope... skip it
	in	al,i4rint		; get receive interrupt status
	cmp	cl,7			; is this the second board ?
	jg	rscnd			; yeap, test that mask
	and	al,bl			; did interrupt occur here ?
	je	nxtsn			;   No, Scan next user
	jmps	rget			; yes, go get the sucker
rscnd:	and	al,bh			; did interrupt occur on second board?
	je	nxtsn			; nope, scan next one
rget:	call	getchr			;   yes, get character to que
nxtsn:	dec	cl			; next relative users turn
	jne	rescan			; go and scan him
	ret
;
;
;
getchr: in	al,i4data		; Read the character
	push	cx			; save for later
	call	conrtc			; convert exact user to device #
	mov	bl,cl			; make index
	xor	bh,bh			; to handshake table
	test	byte ptr hndshk[bx],2	; XON-XOFF handshaking active ?
	je	noxoff			; nope... dont filter XON/XOFF
	cmp	al,xoff			; handshaking active, is it Xoff?
	jne	xontst			; nope test for Xon
	or	byte ptr hndshk[bx],128 ; yeap, set xoff received flag for dev.
xontst: cmp	al,xon			; is it XON ?
	jne	noxoff			; nope... just a character
	and	byte ptr hndshk[bx],7fh ; yeap, clear xoff flag
	jmps	getd			; and we are done

noxoff: call	mapctq			; get offset for q
	call	queins			; insert the character into que
	mov	dl,fbase		; compute flag for this console
	add	dl,cl
	mov	cl,setf			; and set to wake up proccess waiting
	call	supif			; call MPM supervisor interface
getd:	pop	cx			; restore relative user
	ret



;-----------------------------------------------------------------------;
;									;
; i4tisr:   Transmit buffer empty Interrupt Service Handler		;
;	    Determines which device has pending output and		;
;	    sets flag to wake up the task waiting for the		;
;	    USART Transmit buffer to clear.				;
;									;
;-----------------------------------------------------------------------;
;
;
;
i4tisr: mov	al,8			; read from second board first 
	out	i4slct,al		; read from it
	in	al,i4tint		; get interrupt status
	mov	ah,al			; make it high byte of mask
	xor	al,al			; now its the first boards turn
	out	i4slct,al
	in	al,i4tint		; gotcha
	and	ax, word ptr twmsk	; mask only those that are wanted
	mov	dx,1			; dx = mask 
	mov	bl,0			; bl = exact user

tscn:	test	ax,dx			; is he ready
	jnz	txver			; yeap... go get him
	rol	dx,1			; next port
	inc	bl
	cmp	bl,16			; all done ?
	jb	tscn			; nope, keep going till we got the one

txver:	not	dx			; set bit to NOT active for this port
	and	dx,word ptr twmsk
	mov	word ptr twmsk,dx	; update mask
	mov	al,8			; second board first
	out	i4slct,al
	mov	al,dh			; and tx int mask on port
	out	i4tint,al
	xor	al,al			; now first board
	out	i4slct,al
	mov	al,dl
	out	i4tint,al
	mov	cl,bl			; now set flag
	call	conrtc			; for this device
	mov	dl,fbase+16
	add	dl,cl
	mov	cl,setf
	jmp	supif
;
;
;
twmsk	dw	0			; bit map keeping track of which device
					; is waiting for transmit to clear


;-----------------------------------------------------------------------;
;									;
; conrtc: Convert Exact user to Console number				;
;	  The conversion is not always a MPM console number.		;
;	  If a exact user port is a Printer port then the a console	;
;	  Number returned is equal to HIGHCON + PRINTER NUMBER		;
;	  as the hardware handling of printer and consoles is		;
;	  identical, the same routines may be used without having to	;
;	  make exceptions for printer devices. THUS --> IF THE		;
;	  RETURNED CONSOLE NUMBER IS GREATER THAN THE HIGHEST CONSOLE	;
;	  NUMBER SUPPORTED, IT IS A PRINTER.				;
;									;
; Entry	 -> cl = exact Interfacer 3/4 user number			;
;									;
; Return -> cl = Corresponding Console/Device number			;
;									;
;-----------------------------------------------------------------------;
;
;
conrtc: push	bx		; save him
	mov	bl,cl		; make 16 bit of user number
	xor	bh,bh
	mov	cl,rtcmap[bx]	; get corresponding console number
	pop	bx
	ret


rtcmap	db	6		; exact user 0 --> console 6
	db	5		; exact user 1 --> console 5
	db	4		; exact user 2 --> console 4
	db	3		; exact user 3 --> console 3
	db	14		; exact user 4 --> printer 0 (uses que 14)
	db	15		; exact user 5 --> printer 1 (uses que 15)
	db	2		; exact user 6 --> console 2
	db	1		; exact user 7 --> console 1
	db	16		; exact user 8 --> printer 2 (uses que 16)
	db	7		; exact user 9 --> console 7
	db	8		; exact user A --> console 8
	db	9		; exact user B --> console 9
	db	10		; exact user C --> console 10
	db	11		; exact user D --> console 11
	db	12		; exact user E --> console 12
	db	13		; exact user F --> console 13



;-----------------------------------------------------------------------;
;									;
; conctr:	Convert Console to exact user number.			;
;		Performs the inverse function of conrtc.		;
;									;
; entry	 ->   cl = Device/Console number				;
;									;
; return ->   cl = Interfacer 3/4 user number				;
;									;
;-----------------------------------------------------------------------;
;
;
;
conctr: push	bx			; save'm
	xor	bx,bx
	sub	cl,lowcon		; compute 16 bit index to table
	mov	bl,cl
	mov	cl,ctrmap[bx]		; get user number from the table
	pop	bx
	ret				; and we are done
;
;
ctrmap	db	7			; Console 1 ---> exact user 7
	db	6			; Console 2 ---> exact user 6
	db	3			; Console 3 ---> exact user 3
	db	2			; Console 4 ---> exact user 2
	db	1			; Console 5 ---> exact user 1
	db	0			; Console 6 ---> exact user 0
	db	9			; console 7 ---> exact user 9
	db	10			; console 8 ---> exact user 10
	db	11			; console 9 ---> exact user 11
	db	12			; console 10 --> exact user 12
	db	13			; console 11 --> exact user 13
	db	14			; console 12 --> exact user 14
	db	15			; console 13 --> exact user 15
	db	4			; Printer 0 ---> exact user 4
	db	5			; Printer 1 ---> exact user 5
	db	8			; Printer 2 ---> exact user 8



;-----------------------------------------------------------------------;
;									;
; select:      Selects relative user on Interfacer 3/4 board		;
;									;
; Entry	  ->  cl = relative user number					;
;									;
; Return  ->  none							;
;									;
;-----------------------------------------------------------------------;
;
;
;
select: push	ax
	mov	al,cl			; send relative user number to
	out	i4slct,al		; select port
	pop	ax
	ret



;-----------------------------------------------------------------------;
;  qempt:     Checks if que is empty.					;
;									;
;  entry  -> si = que offset						;
;									;
;  return -> Que empty:	   al = 0, Z is Set				;
;	     Char in que:  al = FF, Z not set				;
;-----------------------------------------------------------------------;


qempt:	push	bx		; lets not destroy anything other than al
	mov	bx,cs:word ptr 2[si]	; get rear of que
	cmp	cs:word ptr[si],bx	; if front = rear then
	mov	al, 0
	je	qstat			;   que := empty
	mov	al, 0ffh		; else que:= not empty
qstat:	pop	bx
	or	al,al
	ret

;-----------------------------------------------------------------------;
; qfull:  test if que is full.						;
;									;
; entry	 -> si = que offset						;
;									;
; return -> NZ = ok, Z = que FULL					;
;									;
;-----------------------------------------------------------------------;

qfull: mov	bx,cs:word ptr[si]	; if front + 1 = rear then
       call	incqptr			;   que=full
       cmp	bx,cs:word ptr 2[si]
       ret				; Z = full, NZ = ok


;-----------------------------------------------------------------------;
; incqptr:  Increment the Que pointer. Takes care of wrap arround	;
;	    if end of que area is reached				;
; entry	  -> BX = pointer						;
; return  -> BX = pointer + 1 increment					;
;-----------------------------------------------------------------------;
;
;
incqptr:inc	bx			; point to next que offset
	cmp	bx,qdepth		; end of que area reached ?
	jne	incd			; if not we are done
	xor	bx,bx			; yeap... lets wrap
incd:	ret



;-----------------------------------------------------------------------;
; queins: insert a character into que. If que is full the character	;
;	  is just droped.						;
;									;
; entry	    -> al = character						;
;	       si = que offset						;
;									;
; return -> none							;
;-----------------------------------------------------------------------;

queins: push	ax
	call	qfull			; find out if the que is full
	pop	ax			; Z -> ok, NZ -> full
	je	qind			; if que is full then loos data
	mov	bx,cs: word ptr[si]	; else que[front]=item
	mov	cs:byte ptr 4[si+bx],al
	call	incqptr			; front = front + 1
	mov	cs:word ptr[si],bx
qind:	ret


;-----------------------------------------------------------------------;
; qdel:	 delete a character from que					;
;									;
; entry	   -> si = que offset						;
;									;
; return   -> al = character						;
;-----------------------------------------------------------------------;


qdel:	call	qempt			; anything in the que ?
	je	qdeld			; nope, so nothing we can get out...
	mov	bx,cs:word ptr 2[si]	; al = que[rear]
	mov	al,cs:byte ptr 4[si+bx]
	call	incqptr			; rear = rear+1
	mov	cs:word ptr 2[si],bx
qdeld:	ret


que1	dw	0		; front of que
	dw	0		; rear of que
	rb	qdepth		; here is the que area.

que2	dw	0		; front of que
	dw	0		; rear of que
	rb	qdepth		; here is the que area.

que3	dw	0		; front of que
	dw	0		; rear of que
	rb	qdepth		; here is the que area.

que4	dw	0		; front of que
	dw	0		; rear of que
	rb	qdepth		; here is the que area.

que5	dw	0		; front of que
	dw	0		; rear of que
	rb	qdepth		; here is the que area.

que6	dw	0		; front of que
	dw	0		; rear of que
	rb	qdepth		; here is the que area.

que7	dw	0		; front of que
	dw	0		; rear of que
	rb	qdepth		; here is the que area.

que8	dw	0		; front of que
	dw	0		; rear of que
	rb	qdepth		; here is the que area.

que9	dw	0		; front of que
	dw	0		; rear of que
	rb	qdepth		; here is the que area.

que10	dw	0		; front of que
	dw	0		; rear of que
	rb	qdepth		; here is the que area.

que11	dw	0		; front of que
	dw	0		; rear of que
	rb	qdepth		; here is the que area.

que12	dw	0		; front of que
	dw	0		; rear of que
	rb	qdepth		; here is the que area.

que13	dw	0		; front of que
	dw	0		; rear of que
	rb	qdepth		; here is the que area.

que14	dw	0		; front of que
	dw	0		; rear of que
	rb	qdepth		; here is the que area.

que15	dw	0		; front of que
	dw	0		; rear of que
	rb	qdepth		; here is the que area.

que16	dw	0		; front of que
	dw	0		; rear of que
	rb	qdepth		; here is the que area.



;-----------------------------------------------------------------------;
;									;
; Service:  Called from interrupt routines to save the state of		;
;	    the machine and call the selected interrupt service		;
;	    routine.  After completion of the service routine		;
;	    it restores the state of the machine and jumps to		;
;	    the dispatcher to return from the interrupt.		;
;									;
;  Entry  ->	Old DX pushed on the stack				;
;		DX = Address of the interrupt service routine		;
;									;
;-----------------------------------------------------------------------;
;
;
;
service:push	ds			;Save machine state
	mov	cs:word ptr intss,ss
	mov	cs:word ptr intsp,sp
	mov	cs:word ptr axsave,ax
	mov	ax,cs
	mov	ds,ax				; 8080 model  cs=ds
	mov	ss,ax				; Set up local stack
	mov	sp,offset istack
	push	word ptr axsave			; Save all the registers
	push	bx
	push	cx
	push	bp
	push	si
	push	di
	push	es

	call	dx				; Call ISR

	mov	al,nseoi			; Send End Of Int. to PIC's
	out	mpic0,al			; Master PIC

	pop	es				; Restore machine state
	pop	di
	pop	si
	pop	bp
	pop	cx
	pop	bx
	pop	ax
	mov	ss,word ptr intss
	mov	sp,word ptr intsp
	pop	ds
	pop	dx
	jmpf	cs:dword ptr disp		; Jump to MP/M dispatcher



;-----------------------------------------------------------------------;
;									;
; supif:  Call MP/M supervisor.						;
;									;
; Entry	 ->	CX = Function #						;
;		DX = Parameter						;
;									;
; Return ->	AX = Return value					;
;		BX = AX							;
;		CX = RTM error code					;
;									;
;-----------------------------------------------------------------------;
;
;
;
supif:	mov	ch,0		;Clear high byte of function number
	push	es
	push	ds
	mov	ds,word ptr sysdat
	mov	si,.68h
	mov	es,ds:10h[si]		; get uda of current proccess
	callf	cs:dword ptr supvsr
	pop	ds
	pop	es
	ret



xios	dw	0		;Offset address of XIOS
sysdat	dw	0		;Segment of XIOS and system data segment

supvsr	dw	3		;Entry to the supervisor = offset 3
	dw	0		;Segment filled in later

disp	dw	0		; MPM dispatcher offset
	dw	0		; and segment

axsave	dw	0		; save area for AX
intss	dw	0		; SS
intsp	dw	0		; and SP  for ISRs


	rb	128
istack	db	0		; Stack for interrupt service

	rb	128		; Make sure to allow enough stack space
lstack	db	0		; stack for MSUP execution entry point




	dseg

	org	0h	; 0 if used as RSP

;
; RSP header
;

sdatseg dw	0,0,0
	dw	0,0,0
	dw	0,0

	org	10h
	
pd	dw	0,0		;Link,thread
	db	0		;Status
	db	190		;Priority
	dw	5		;Flags
	db	'Msup    '	;Name
	dw	offset uda/10h	;Uda seg
	db	0,0		;Disk,user
	db	0,0		;Load dsk,usr
	dw	0		;Mem
	dw	0,0		;Dvract,wait
	db	0,0
	dw	0
	db	0		;Console
	db	0,0,0
	db	0		;List
	db	0,0,0
	dw	0,0,0,0

	org	40h
	
uda	dw	0,0,0,0		;0
	dw	0,0,0,0
	dw	0,0,0,0		;10h
	dw	0,0,0,0
	dw	0,0,0,0		;20h
	dw	0,0,0,0
	dw	0,0,offset stack,0 ;30h
	dw	0,0,0,0 
	dw	0,0,0,0		;40h
	dw	0,0,0,0
	dw	0,0,0,0		;50h
	dw	0,0,0,0
	dw	0,0,0,0		;60h

	org	140h

	dw	0cccch,0cccch,0cccch
	dw	0cccch,0cccch,0cccch
	dw	0cccch,0cccch,0cccch
	dw	0cccch,0cccch,0cccch
	dw	0cccch,0cccch,0cccch
stack	dw	offset exec	;Start offset
	dw	0		;Start seg
	dw	0		;Init flags


	end	

